// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package sync

import (
	"internal/race"
	"runtime"
	"sync/atomic"
	"unsafe"
)

// 池是一组可以单独保存和检索的临时对象。
// 
// 存储在池中的任何项目都可以随时自动删除，而无需
// 通知。如果发生这种情况时池持有唯一引用，则
// 项可能被解除分配。
// 
// 一个池可供多个goroutine同时使用。
// 
// 池的目的是缓存已分配但未使用的项，以便以后重用，
// 减轻垃圾收集器的压力。也就是说，它使
// 构建高效、线程安全的自由列表变得容易。但是，它并不适用于所有
// 自由列表。
// 
// 池的适当用途是管理一组临时项
// 在包的并发独立
// 客户端之间静默共享并可能由其重用。Pool提供了一种在多个客户之间分摊分配开销
// 的方法。
// 
// 一个很好地使用池的例子是在fmt包中，它维护一个动态大小的临时输出缓冲区存储。存储在
// 加载（当许多goroutine正在进行打印时）下扩展，在
// 静止时缩小。
// 
// 另一方面，作为短期对象的一部分维护的自由列表是
// 不适合用于池，因为在
// 这种情况下，开销不会很好地摊销。让这些对象实现自己的
// 自由列表更有效。
// 
// 池首次使用后不得复制。
type Pool struct {
	noCopy noCopy

	local     unsafe.Pointer // 每P池的本地固定大小，实际类型为[P]池本地
	localSize uintptr        // 本地数组的大小

	victim     unsafe.Pointer // 上一个周期的本地
	victimSize uintptr        // 受害者数组的大小

	// New可选指定一个函数来生成
	// 否则Get将返回零时的值。
	// 它不能与Get调用同时更改。
	New func() interface{}
}

// 本地per-P池附录。
type poolLocalInternal struct {
	private interface{} // 只能由相应的P使用。
	shared  poolChain   // 本地P Can推杆/popHead；任何P都可以用爆米花。
}

type poolLocal struct {
	poolLocalInternal

	// 使用
	// 128 mod（缓存线大小）=0在广泛的平台上防止错误共享。
	pad [128 - unsafe.Sizeof(poolLocalInternal{})%128]byte
}

// 从运行时开始
func fastrand() uint32

var poolRaceHash [128]uint64

// poolRaceAddr返回一个地址，用作竞态检测器逻辑的同步点
// 。我们不直接使用存储在x 
// /中的实际指针，以免与该地址上的其他同步冲突。
// 相反，我们对指针进行散列，以将索引放入poolRaceHash中。
// 见golang.org/cl/31589上的讨论。
func poolRaceAddr(x interface{}) unsafe.Pointer {
	ptr := uintptr((*[2]unsafe.Pointer)(unsafe.Pointer(&x))[1])
	h := uint32((uint64(uint32(ptr)) * 0x85ebca6b) >> 16)
	return unsafe.Pointer(&poolRaceHash[h%uint32(len(poolRaceHash))])
}

// Put将x添加到池中。
func (p *Pool) Put(x interface{}) {
	if x == nil {
		return
	}
	if race.Enabled {
		if fastrand()%4 == 0 {
			// 随机将x掉落在地板上。
			return
		}
		race.ReleaseMerge(poolRaceAddr(x))
		race.Disable()
	}
	l, _ := p.pin()
	if l.private == nil {
		l.private = x
		x = nil
	}
	if x != nil {
		l.shared.pushHead(x)
	}
	runtime_procUnpin()
	if race.Enabled {
		race.Enable()
	}
}

// Get从池中选择任意项，将其从
// 池中删除，并将其返回给调用方。
// Get可以选择忽略池并将其视为空。
// 调用方不应假定传递给Put的值与
// Get返回的值之间存在任何关系。
// 
// 如果Get返回nil而p.New为非nil，则Get返回
// 调用p.New的结果。
func (p *Pool) Get() interface{} {
	if race.Enabled {
		race.Disable()
	}
	l, pid := p.pin()
	x := l.private
	l.private = nil
	if x == nil {
		// 尝试弹出本地碎片的头部。对于
		// 从头到尾。
		// 重用的时间位置，我们更喜欢
		x, _ = l.shared.popHead()
		if x == nil {
			x = p.getSlow(pid)
		}
	}
	runtime_procUnpin()
	if race.Enabled {
		race.Enable()
		if x != nil {
			race.Acquire(poolRaceAddr(x))
		}
	}
	if x == nil && p.New != nil {
		x = p.New()
	}
	return x
}

func (p *Pool) getSlow(pid int) interface{} {
	// 请参阅pin中有关荷载顺序的注释。
	size := runtime_LoadAcquintptr(&p.localSize) // 加载获取
	locals := p.local                            // 加载消耗
	// 尝试从其他进程中窃取一个元素。
	for i := 0; i < int(size); i++ {
		l := indexLocal(locals, (pid+i+1)%int(size))
		if x, _ := l.shared.popTail(); x != nil {
			return x
		}
	}

	// 尝试受害者缓存。我们在尝试从所有主缓存中窃取
	// 后执行此操作，因为我们希望
	// 受害者缓存中的对象尽可能老化。
	size = atomic.LoadUintptr(&p.victimSize)
	if uintptr(pid) >= size {
		return nil
	}
	locals = p.victim
	l := indexLocal(locals, pid)
	if x := l.private; x != nil {
		l.private = nil
		return x
	}
	for i := 0; i < int(size); i++ {
		l := indexLocal(locals, (pid+i)%int(size))
		if x, _ := l.shared.popTail(); x != nil {
			return x
		}
	}

	// 将受害者缓存标记为空，以备将来获取。不要用它来麻烦
	// 。
	atomic.StoreUintptr(&p.victimSize, 0)

	return nil
}

// 将当前goroutine固定到P，禁用抢占，并返回P和P的id的poolLocal池。
// 调用程序在处理池时必须调用runtime_procupin（）。
func (p *Pool) pin() (*poolLocal, int) {
	pid := runtime_procPin()
	// 在pinSlow中，我们先存储到local，然后存储到localSize，在这里我们按相反的顺序加载。
	// 由于我们禁用了抢占，GC不能在两者之间发生。
	// 因此，在这里，我们必须观察本地大小，至少与localSize一样大。
	// 我们可以观察一个新的/更大的本地，这很好（我们必须观察它的零度）。
	s := runtime_LoadAcquintptr(&p.localSize) // 加载获取
	l := p.local                              // 加载消耗
	if uintptr(pid) < s {
		return indexLocal(l, pid), pid
	}
	return p.pinSlow()
}

func (p *Pool) pinSlow() (*poolLocal, int) {
	// 在互斥锁下重试。
	// 锁定时无法锁定互斥锁。
	runtime_procUnpin()
	allPoolsMu.Lock()
	defer allPoolsMu.Unlock()
	pid := runtime_procPin()
	// 锁定时将不会调用池清理。
	s := p.localSize
	l := p.local
	if uintptr(pid) < s {
		return indexLocal(l, pid), pid
	}
	if p.local == nil {
		allPools = append(allPools, p)
	}
	// 如果在地面军事系统之间更改GOMAXPROCS，我们将重新分配阵列并丢失旧阵列。
	size := runtime.GOMAXPROCS(0)
	local := make([]poolLocal, size)
	atomic.StorePointer(&p.local, unsafe.Pointer(&local[0])) // 存储释放
	runtime_StoreReluintptr(&p.localSize, uintptr(size))     // 存储释放
	return &local[pid], pid
}

func poolCleanup() {
	// 在垃圾收集开始时，在世界停止的情况下调用此函数。
	// 它不能分配，也可能不应该调用任何运行时函数。

	// 因为世界已停止，所以池用户不能位于
	// 已锁定部分（实际上，这已锁定所有Ps）。

	// 从所有池中删除受害者缓存。
	for _, p := range oldPools {
		p.victim = nil
		p.victimSize = 0
	}

	// 将主缓存移动到受害者缓存。
	for _, p := range allPools {
		p.victim = p.local
		p.victimSize = p.localSize
		p.local = nil
		p.localSize = 0
	}

	// 具有非空主缓存的池现在具有非空
	// 受害者缓存，并且没有池具有主缓存。
	oldPools, allPools = allPools, nil
}

var (
	allPoolsMu Mutex

	// 所有池是具有非空主
	// 缓存的池集。受1）ALLPOLSMU和钉扎或2）
	// STW保护。
	allPools []*Pool

	// oldPools是可能具有非空牺牲品
	// 缓存的池集。受STW保护。
	oldPools []*Pool
)

func init() {
	runtime_registerPoolCleanup(poolCleanup)
}

func indexLocal(l unsafe.Pointer, i int) *poolLocal {
	lp := unsafe.Pointer(uintptr(l) + uintptr(i)*unsafe.Sizeof(poolLocal{}))
	return (*poolLocal)(lp)
}

// 在运行时实现。
func runtime_registerPoolCleanup(cleanup func())
func runtime_procPin() int
func runtime_procUnpin()

// 以下是在运行时/内部/原子中实现的，并且
// 编译器也知道将我们链接到这个
// 包中的符号进行内部化。

// go:linkname runtime\u LoadAcquintptr runtime/internal/atomic.LoadAcquintptr 
func runtime_LoadAcquintptr(ptr *uintptr) uintptr

// go:linkname runtime\u StoreReluintptr runtime/internal/atomic.StoreReluintptr 
func runtime_StoreReluintptr(ptr *uintptr, val uintptr) uintptr
